﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Animation;
using Algoritmia.DataStructures.Lists;
using Algoritmia.Problems.Knapsack;

namespace Demos.Knapsack
{
    class ViewModel: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public ObservableCollection<ElementoVisual> ContenidoVisual { get; set; }

        private double _maxX;
        public double MaxX 
        { 
            get { return _maxX; }
            set 
            { 
                _maxX = value;
                ContenidoVisual.Last().X = (MaxX / 2) - 65;
            }
        }
        public double MaxY { get; set; }

        private string _contenidoNuevo;
        public string ContenidoNuevo
        {
            get { return _contenidoNuevo; }
            set
            {
                _contenidoNuevo = value;
                NotifyPropertyChanged("ContenidoNuevo");
            }
        }

        private string _valorNuevo;
        public string ValorNuevo
        {
            get { return _valorNuevo; }
            set
            {
                _valorNuevo = value;
                NotifyPropertyChanged("ValorNuevo");
            }
        }

        private string _pesoNuevo;
        public string PesoNuevo
        {
            get { return _pesoNuevo; }
            set
            {
                _pesoNuevo = value;
                NotifyPropertyChanged("PesoNuevo");
            }
        }

        public ICommand AñadirObjetoCommand { get; private set; }
        public ICommand EjecutarCommand { get; private set; }
        public ICommand BorrarTodoCommand { get; private set; }

        private readonly KnapsackSolver _model;
        private const int DuracionMilisegundos = 400;


        public ViewModel(KnapsackSolver model)
        {
            _model = model;
            ContenidoVisual = new ObservableCollection<ElementoVisual>{new Mochila(50, 30, 10)};

            AñadirObjetoCommand = new RelayCommand(AñadirObjeto, () => !string.IsNullOrEmpty(ContenidoNuevo));
            EjecutarCommand = new RelayCommand(Ejecutar, () => ContenidoVisual.Count > 1 && 
                                               string.IsNullOrEmpty((ContenidoVisual.Last() as Mochila).Contenido));
            BorrarTodoCommand = new RelayCommand(BorrarTodo, () => ContenidoVisual.Count > 1);

            //Objetos de ejemplo
            ContenidoNuevo = "Aspirador";
            ValorNuevo = "5";
            PesoNuevo = "10";
            AñadirObjetoCommand.Execute(null);

            ContenidoNuevo = "Canicas";
            ValorNuevo = "1";
            PesoNuevo = "1";
            AñadirObjetoCommand.Execute(null);

            ContenidoNuevo = "Diamante";
            ValorNuevo = "10";
            PesoNuevo = "2";
            AñadirObjetoCommand.Execute(null);

            ContenidoNuevo = "MacBook";
            ValorNuevo = "2";
            PesoNuevo = "3";
            AñadirObjetoCommand.Execute(null);

            ContenidoNuevo = "TV";
            ValorNuevo = "4";
            PesoNuevo = "4";
            AñadirObjetoCommand.Execute(null);
        }


        private void Ejecutar()
        {
            var valores = new ArrayList<double>();
            var pesos = new ArrayList<int>();

            for (var i = 0; i < ContenidoVisual.Count-1; i++)
            {
                valores.Add((ContenidoVisual[i] as Objeto).Valor);
                pesos.Add((ContenidoVisual[i] as Objeto).Peso);
            }

            var solucion = _model.Decisions((ContenidoVisual.Last() as Mochila).Capacidad, valores, pesos);
            ActualizarContenidoMochila(solucion);
        }

        private void ActualizarContenidoMochila(IEnumerable<int> solucion)
        {
            double total = 0;
            for (var i = 0; i < solucion.Count(); i++)
            {
                if (solucion.ElementAt(i) == 1)
                {
                    (ContenidoVisual.Last() as Mochila).Contenido += string.Format("{0} ({1} Kg, {2} €)\n",
                        (ContenidoVisual[i] as Objeto).Contenido, (ContenidoVisual[i] as Objeto).Peso, (ContenidoVisual[i] as Objeto).Valor);
                    (ContenidoVisual.Last() as Mochila).Capacidad -= (ContenidoVisual[i] as Objeto).Peso;
                    total += (ContenidoVisual[i] as Objeto).Valor;
                    MeterEnMochila(i);
                }
            }
            (ContenidoVisual.Last() as Mochila).Contenido += string.Format("Total: {0} €", total);
        }

        private void MeterEnMochila(int i)
        {
            var duration1 = new Duration(TimeSpan.FromMilliseconds(DuracionMilisegundos));
            var sb1 = new Storyboard();
            var myDoubleAnimation1 = new DoubleAnimation();
            var myDoubleAnimation2 = new DoubleAnimation();
            var myDoubleAnimation3 = new DoubleAnimation();

            myDoubleAnimation1.Duration = duration1;
            myDoubleAnimation2.Duration = duration1;
            myDoubleAnimation3.Duration = duration1;
            sb1.Duration = duration1;
            sb1.Children.Add(myDoubleAnimation1);
            sb1.Children.Add(myDoubleAnimation2);
            sb1.Children.Add(myDoubleAnimation3);
            Storyboard.SetTarget(myDoubleAnimation1, ContenidoVisual[i]);
            Storyboard.SetTarget(myDoubleAnimation2, ContenidoVisual[i]);
            Storyboard.SetTarget(myDoubleAnimation3, ContenidoVisual[i]);
            Storyboard.SetTargetProperty(myDoubleAnimation1, new PropertyPath("(X)"));
            Storyboard.SetTargetProperty(myDoubleAnimation2, new PropertyPath("(Y)"));
            Storyboard.SetTargetProperty(myDoubleAnimation3, new PropertyPath("(Opacidad)"));
            myDoubleAnimation1.From = ContenidoVisual[i].X;
            myDoubleAnimation1.To = ContenidoVisual.Last().X;
            myDoubleAnimation2.From = ContenidoVisual[i].Y;
            myDoubleAnimation2.To = ContenidoVisual.Last().Y;
            myDoubleAnimation3.From = 1;
            myDoubleAnimation3.To = 0;

            sb1.Begin();
        }

        private void AñadirObjeto()
        {
            try
            {
                double valor = 1;
                if (!string.IsNullOrEmpty(ValorNuevo))
                {
                    valor = double.Parse(ValorNuevo);
                }
                int peso = 1;
                if (!string.IsNullOrEmpty(PesoNuevo))
                {
                    peso = int.Parse(PesoNuevo);
                }

                ContenidoVisual.Insert(0, new Objeto(100*(ContenidoVisual.Count-1), 200, ContenidoNuevo, valor, peso));

                ContenidoNuevo = "";
                ValorNuevo = "";
                PesoNuevo = "";
            }
            catch (FormatException)
            {
                MessageBox.Show("Formato incorrecto", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void BorrarTodo()
        {
            var mochila = ContenidoVisual.Last();
            ContenidoVisual.Clear();
            ContenidoVisual.Add(mochila);
            (ContenidoVisual.Last() as Mochila).Contenido = "";
        }
    }
}
